// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef EIGEN_BINARY_FUNCTORS_H
#define EIGEN_BINARY_FUNCTORS_H

namespace Eigen {

namespace internal {

//---------- associative binary functors ----------

template<typename Arg1, typename Arg2>
struct binary_op_base
{
	typedef Arg1 first_argument_type;
	typedef Arg2 second_argument_type;
};

/** \internal
 * \brief Template functor to compute the sum of two scalars
 *
 * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, DenseBase::sum()
 */
template<typename LhsScalar, typename RhsScalar>
struct scalar_sum_op : binary_op_base<LhsScalar, RhsScalar>
{
	typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_sum_op>::ReturnType result_type;
#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN
	EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op)
#else
	scalar_sum_op() {
    EIGEN_SCALAR_BINARY_OP_PLUGIN
  }
#endif
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a + b;
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::padd(a, b);
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
	{
		return internal::predux(a);
	}
};
template<typename LhsScalar, typename RhsScalar>
struct functor_traits<scalar_sum_op<LhsScalar, RhsScalar>>
{
	enum
	{
		Cost = (int(NumTraits<LhsScalar>::AddCost) + int(NumTraits<RhsScalar>::AddCost)) / 2, // rough estimate!
		PacketAccess =
			is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasAdd && packet_traits<RhsScalar>::HasAdd
		// TODO vectorize mixed sum
	};
};

template<>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool
scalar_sum_op<bool, bool>::operator()(const bool& a, const bool& b) const
{
	return a || b;
}

/** \internal
 * \brief Template functor to compute the product of two scalars
 *
 * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux()
 */
template<typename LhsScalar, typename RhsScalar>
struct scalar_product_op : binary_op_base<LhsScalar, RhsScalar>
{
	typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_product_op>::ReturnType result_type;
#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN
	EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op)
#else
	scalar_product_op() {
    EIGEN_SCALAR_BINARY_OP_PLUGIN
  }
#endif
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a * b;
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::pmul(a, b);
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
	{
		return internal::predux_mul(a);
	}
};
template<typename LhsScalar, typename RhsScalar>
struct functor_traits<scalar_product_op<LhsScalar, RhsScalar>>
{
	enum
	{
		Cost = (int(NumTraits<LhsScalar>::MulCost) + int(NumTraits<RhsScalar>::MulCost)) / 2, // rough estimate!
		PacketAccess =
			is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMul && packet_traits<RhsScalar>::HasMul
		// TODO vectorize mixed product
	};
};

template<>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool
scalar_product_op<bool, bool>::operator()(const bool& a, const bool& b) const
{
	return a && b;
}

/** \internal
 * \brief Template functor to compute the conjugate product of two scalars
 *
 * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x
 * * conj(y)
 */
template<typename LhsScalar, typename RhsScalar>
struct scalar_conj_product_op : binary_op_base<LhsScalar, RhsScalar>
{

	enum
	{
		Conj = NumTraits<LhsScalar>::IsComplex
	};

	typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_conj_product_op>::ReturnType result_type;

	EIGEN_EMPTY_STRUCT_CTOR(scalar_conj_product_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return conj_helper<LhsScalar, RhsScalar, Conj, false>().pmul(a, b);
	}

	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
	{
		return conj_helper<Packet, Packet, Conj, false>().pmul(a, b);
	}
};
template<typename LhsScalar, typename RhsScalar>
struct functor_traits<scalar_conj_product_op<LhsScalar, RhsScalar>>
{
	enum
	{
		Cost = NumTraits<LhsScalar>::MulCost,
		PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMul
	};
};

/** \internal
 * \brief Template functor to compute the min of two scalars
 *
 * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff()
 */
template<typename LhsScalar, typename RhsScalar, int NaNPropagation>
struct scalar_min_op : binary_op_base<LhsScalar, RhsScalar>
{
	typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_min_op>::ReturnType result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return internal::pmin<NaNPropagation>(a, b);
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::pmin<NaNPropagation>(a, b);
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
	{
		return internal::predux_min<NaNPropagation>(a);
	}
};

template<typename LhsScalar, typename RhsScalar, int NaNPropagation>
struct functor_traits<scalar_min_op<LhsScalar, RhsScalar, NaNPropagation>>
{
	enum
	{
		Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
		PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMin
	};
};

/** \internal
 * \brief Template functor to compute the max of two scalars
 *
 * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff()
 */
template<typename LhsScalar, typename RhsScalar, int NaNPropagation>
struct scalar_max_op : binary_op_base<LhsScalar, RhsScalar>
{
	typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_max_op>::ReturnType result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return internal::pmax<NaNPropagation>(a, b);
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::pmax<NaNPropagation>(a, b);
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type predux(const Packet& a) const
	{
		return internal::predux_max<NaNPropagation>(a);
	}
};

template<typename LhsScalar, typename RhsScalar, int NaNPropagation>
struct functor_traits<scalar_max_op<LhsScalar, RhsScalar, NaNPropagation>>
{
	enum
	{
		Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
		PacketAccess = internal::is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasMax
	};
};

/** \internal
 * \brief Template functors for comparison of two scalars
 * \todo Implement packet-comparisons
 */
template<typename LhsScalar, typename RhsScalar, ComparisonName cmp>
struct scalar_cmp_op;

template<typename LhsScalar, typename RhsScalar, ComparisonName cmp>
struct functor_traits<scalar_cmp_op<LhsScalar, RhsScalar, cmp>>
{
	enum
	{
		Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
		PacketAccess = false
	};
};

template<ComparisonName Cmp, typename LhsScalar, typename RhsScalar>
struct result_of<scalar_cmp_op<LhsScalar, RhsScalar, Cmp>(LhsScalar, RhsScalar)>
{
	typedef bool type;
};

template<typename LhsScalar, typename RhsScalar>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_EQ> : binary_op_base<LhsScalar, RhsScalar>
{
	typedef bool result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a == b;
	}
};
template<typename LhsScalar, typename RhsScalar>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LT> : binary_op_base<LhsScalar, RhsScalar>
{
	typedef bool result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a < b;
	}
};
template<typename LhsScalar, typename RhsScalar>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LE> : binary_op_base<LhsScalar, RhsScalar>
{
	typedef bool result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a <= b;
	}
};
template<typename LhsScalar, typename RhsScalar>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GT> : binary_op_base<LhsScalar, RhsScalar>
{
	typedef bool result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a > b;
	}
};
template<typename LhsScalar, typename RhsScalar>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GE> : binary_op_base<LhsScalar, RhsScalar>
{
	typedef bool result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a >= b;
	}
};
template<typename LhsScalar, typename RhsScalar>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_UNORD> : binary_op_base<LhsScalar, RhsScalar>
{
	typedef bool result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return !(a <= b || b <= a);
	}
};
template<typename LhsScalar, typename RhsScalar>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_NEQ> : binary_op_base<LhsScalar, RhsScalar>
{
	typedef bool result_type;
	EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a != b;
	}
};

/** \internal
 * \brief Template functor to compute the hypot of two \b positive \b and \b real scalars
 *
 * \sa MatrixBase::stableNorm(), class Redux
 */
template<typename Scalar>
struct scalar_hypot_op<Scalar, Scalar> : binary_op_base<Scalar, Scalar>
{
	EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op)

	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& x, const Scalar& y) const
	{
		// This functor is used by hypotNorm only for which it is faster to first apply abs
		// on all coefficients prior to reduction through hypot.
		// This way we avoid calling abs on positive and real entries, and this also permits
		// to seamlessly handle complexes. Otherwise we would have to handle both real and complexes
		// through the same functor...
		return internal::positive_real_hypot(x, y);
	}
};
template<typename Scalar>
struct functor_traits<scalar_hypot_op<Scalar, Scalar>>
{
	enum
	{
		Cost =
			3 * NumTraits<Scalar>::AddCost + 2 * NumTraits<Scalar>::MulCost + 2 * scalar_div_cost<Scalar, false>::value,
		PacketAccess = false
	};
};

/** \internal
 * \brief Template functor to compute the pow of two scalars
 * See the specification of pow in https://en.cppreference.com/w/cpp/numeric/math/pow
 */
template<typename Scalar, typename Exponent>
struct scalar_pow_op : binary_op_base<Scalar, Exponent>
{
	typedef typename ScalarBinaryOpTraits<Scalar, Exponent, scalar_pow_op>::ReturnType result_type;
#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN
	EIGEN_EMPTY_STRUCT_CTOR(scalar_pow_op)
#else
	scalar_pow_op()
	{
		typedef Scalar LhsScalar;
		typedef Exponent RhsScalar;
		EIGEN_SCALAR_BINARY_OP_PLUGIN
	}
#endif

	EIGEN_DEVICE_FUNC
	inline result_type operator()(const Scalar& a, const Exponent& b) const { return numext::pow(a, b); }

	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
	{
		return generic_pow(a, b);
	}
};

template<typename Scalar, typename Exponent>
struct functor_traits<scalar_pow_op<Scalar, Exponent>>
{
	enum
	{
		Cost = 5 * NumTraits<Scalar>::MulCost,
		PacketAccess =
			(!NumTraits<Scalar>::IsComplex && !NumTraits<Scalar>::IsInteger && packet_traits<Scalar>::HasExp &&
			 packet_traits<Scalar>::HasLog && packet_traits<Scalar>::HasRound && packet_traits<Scalar>::HasCmp &&
			 // Temporarly disable packet access for half/bfloat16 until
			 // accuracy is improved.
			 !is_same<Scalar, half>::value && !is_same<Scalar, bfloat16>::value)
	};
};

//---------- non associative binary functors ----------

/** \internal
 * \brief Template functor to compute the difference of two scalars
 *
 * \sa class CwiseBinaryOp, MatrixBase::operator-
 */
template<typename LhsScalar, typename RhsScalar>
struct scalar_difference_op : binary_op_base<LhsScalar, RhsScalar>
{
	typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_difference_op>::ReturnType result_type;
#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN
	EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op)
#else
	scalar_difference_op() {
    EIGEN_SCALAR_BINARY_OP_PLUGIN
  }
#endif
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a - b;
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::psub(a, b);
	}
};
template<typename LhsScalar, typename RhsScalar>
struct functor_traits<scalar_difference_op<LhsScalar, RhsScalar>>
{
	enum
	{
		Cost = (int(NumTraits<LhsScalar>::AddCost) + int(NumTraits<RhsScalar>::AddCost)) / 2,
		PacketAccess =
			is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasSub && packet_traits<RhsScalar>::HasSub
	};
};

/** \internal
 * \brief Template functor to compute the quotient of two scalars
 *
 * \sa class CwiseBinaryOp, Cwise::operator/()
 */
template<typename LhsScalar, typename RhsScalar>
struct scalar_quotient_op : binary_op_base<LhsScalar, RhsScalar>
{
	typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_quotient_op>::ReturnType result_type;
#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN
	EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op)
#else
	scalar_quotient_op() {
    EIGEN_SCALAR_BINARY_OP_PLUGIN
  }
#endif
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return a / b;
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::pdiv(a, b);
	}
};
template<typename LhsScalar, typename RhsScalar>
struct functor_traits<scalar_quotient_op<LhsScalar, RhsScalar>>
{
	typedef typename scalar_quotient_op<LhsScalar, RhsScalar>::result_type result_type;
	enum
	{
		PacketAccess = is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasDiv &&
					   packet_traits<RhsScalar>::HasDiv,
		Cost = scalar_div_cost<result_type, PacketAccess>::value
	};
};

/** \internal
 * \brief Template functor to compute the and of two booleans
 *
 * \sa class CwiseBinaryOp, ArrayBase::operator&&
 */
struct scalar_boolean_and_op
{
	EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_and_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const bool& a, const bool& b) const { return a && b; }
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::pand(a, b);
	}
};
template<>
struct functor_traits<scalar_boolean_and_op>
{
	enum
	{
		Cost = NumTraits<bool>::AddCost,
		PacketAccess = true
	};
};

/** \internal
 * \brief Template functor to compute the or of two booleans
 *
 * \sa class CwiseBinaryOp, ArrayBase::operator||
 */
struct scalar_boolean_or_op
{
	EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_or_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const bool& a, const bool& b) const { return a || b; }
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::por(a, b);
	}
};
template<>
struct functor_traits<scalar_boolean_or_op>
{
	enum
	{
		Cost = NumTraits<bool>::AddCost,
		PacketAccess = true
	};
};

/** \internal
 * \brief Template functor to compute the xor of two booleans
 *
 * \sa class CwiseBinaryOp, ArrayBase::operator^
 */
struct scalar_boolean_xor_op
{
	EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_xor_op)
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const bool& a, const bool& b) const { return a ^ b; }
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::pxor(a, b);
	}
};
template<>
struct functor_traits<scalar_boolean_xor_op>
{
	enum
	{
		Cost = NumTraits<bool>::AddCost,
		PacketAccess = true
	};
};

/** \internal
 * \brief Template functor to compute the absolute difference of two scalars
 *
 * \sa class CwiseBinaryOp, MatrixBase::absolute_difference
 */
template<typename LhsScalar, typename RhsScalar>
struct scalar_absolute_difference_op : binary_op_base<LhsScalar, RhsScalar>
{
	typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar, scalar_absolute_difference_op>::ReturnType result_type;
#ifndef EIGEN_SCALAR_BINARY_OP_PLUGIN
	EIGEN_EMPTY_STRUCT_CTOR(scalar_absolute_difference_op)
#else
	scalar_absolute_difference_op() {
    EIGEN_SCALAR_BINARY_OP_PLUGIN
  }
#endif
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const LhsScalar& a, const RhsScalar& b) const
	{
		return numext::absdiff(a, b);
	}
	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const
	{
		return internal::pabsdiff(a, b);
	}
};
template<typename LhsScalar, typename RhsScalar>
struct functor_traits<scalar_absolute_difference_op<LhsScalar, RhsScalar>>
{
	enum
	{
		Cost = (NumTraits<LhsScalar>::AddCost + NumTraits<RhsScalar>::AddCost) / 2,
		PacketAccess = is_same<LhsScalar, RhsScalar>::value && packet_traits<LhsScalar>::HasAbsDiff
	};
};

//---------- binary functors bound to a constant, thus appearing as a unary functor ----------

// The following two classes permits to turn any binary functor into a unary one with one argument bound to a constant
// value. They are analogues to std::binder1st/binder2nd but with the following differences:
//  - they are compatible with packetOp
//  - they are portable across C++ versions (the std::binder* are deprecated in C++11)
template<typename BinaryOp>
struct bind1st_op : BinaryOp
{

	typedef typename BinaryOp::first_argument_type first_argument_type;
	typedef typename BinaryOp::second_argument_type second_argument_type;
	typedef typename BinaryOp::result_type result_type;

	EIGEN_DEVICE_FUNC explicit bind1st_op(const first_argument_type& val)
		: m_value(val)
	{
	}

	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const second_argument_type& b) const
	{
		return BinaryOp::operator()(m_value, b);
	}

	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& b) const
	{
		return BinaryOp::packetOp(internal::pset1<Packet>(m_value), b);
	}

	first_argument_type m_value;
};
template<typename BinaryOp>
struct functor_traits<bind1st_op<BinaryOp>> : functor_traits<BinaryOp>
{};

template<typename BinaryOp>
struct bind2nd_op : BinaryOp
{

	typedef typename BinaryOp::first_argument_type first_argument_type;
	typedef typename BinaryOp::second_argument_type second_argument_type;
	typedef typename BinaryOp::result_type result_type;

	EIGEN_DEVICE_FUNC explicit bind2nd_op(const second_argument_type& val)
		: m_value(val)
	{
	}

	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator()(const first_argument_type& a) const
	{
		return BinaryOp::operator()(a, m_value);
	}

	template<typename Packet>
	EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const
	{
		return BinaryOp::packetOp(a, internal::pset1<Packet>(m_value));
	}

	second_argument_type m_value;
};
template<typename BinaryOp>
struct functor_traits<bind2nd_op<BinaryOp>> : functor_traits<BinaryOp>
{};

} // end namespace internal

} // end namespace Eigen

#endif // EIGEN_BINARY_FUNCTORS_H
